import json


class MockItem:
    def __init__(self, data: dict):
        if data:
            self.req: dict = data.get('request', {})
            self.resp: dict = data.get('response', {})
            # django中匹配path是不需要左“/”的
            # 此uri与django的路由表中uri保持一致
            self.uri: str = self.req.get('uri').lstrip('/') if self.req.get('uri') else ''
            if self.req:
                self.req.setdefault('method', 'GET') # 未设置则默认为GET
                self.req['method'] = self.req['method'].upper()
            if self.uri:
                self.req['uri'] = self.uri # 替换原数据中的uri,保证正确性
            else:
                self.uri = self.req['uri'] = self.req.get('re_uri')
                del self.req['re_uri']
        else:
            self.req = {}
            self.resp = {}
            self.uri = ''

    def __str__(self):
        return '< {} uri={} >'.format(self.__class__.__name__, self.uri)

    def __hash__(self):
        return hash(self.__str__())


class BodyHandler:
    body_handler_func = {
        "multipart/form-data": "func1",
        "application/x-www-form-urlencoded": "func2",
        "application/json": "func3",
    }

    @staticmethod
    def func1(req_self):
        req_self.form = req_self._request.POST.dict() if req_self._request.POST else None

    @staticmethod
    def func2(req_self):
        req_self.form = dict([k2v.split('=') for k2v in req_self._body.decode('utf-8').split('&')]) or None

    @staticmethod
    def func3(req_self):
        try:
            req_self.json = json.loads(req_self._body) if req_self._body else None
        except Exception:
            req_self._req['json'] = {}

    @staticmethod
    def other(req_self):
        try:
            req_self.body = req_self._body.decode() if req_self._body else None
        except Exception:
            req_self._req['body']  = ''

    @classmethod
    def handle_body(cls, req_self):
        funcName = cls.body_handler_func.get(req_self._content_type, 'other')
        getattr(cls, funcName)(req_self)


class RequestSerializer:
    def __init__(self, request):
        # 保存数据
        self._request = request
        self._body = self._request.body
        self._path = self._request.get_full_path()
        self._headers = self._request.headers
        self._content_type = self._request.content_type

        # mock文件里请求支持的字段
        self.cookies = self._request.COOKIES if self._request.COOKIES else None
        self.uri = self._request.resolver_match.route # 匹配到的uri pattern 用于匹配mock
        self.method = self._request.method.upper()
        self.queries = self._request.GET.dict() if self._request.GET else None

        BodyHandler.handle_body(self)

    @property
    def req(self):
        return {k: v for k, v in self.__dict__.items() if not k.startswith('_') and v is not None}

    def __str__(self):
        return '< {} path={} >'.format(self.__class__.__name__, self._path)
